#include "GameRoom.h"
#include "PublicMarcos.h"
#include "PlayerObj.h"
#include <algorithm>
#include <boost/mem_fn.hpp>
#include "BgObj.h"
#include "EnermyObj.h"
#include "Environment.h"
#include "ScriptEngine.h"
#include "EndRoom.h"
#include "InsideRoom.h"

float GameRoom::m_livetime = 0.0f;
GameRoom* GameRoom::m_pToDev = NULL;

GameRoom::GameRoom( const char* resName ):m_pickedEnermy(NULL),m_isGameover(false)
{
	m_livetime = 0;
	m_score = 0;
	m_pToDev = this;
	m_Res = new hgeResourceManager(resName);
	m_musicPlayer = Environment::PlayMusic(m_Res->GetStream("BGM"),true,80);
	AddGameObj(new BgObj(m_Res->GetSprite("corebackground"),0,0,false));
	AddGameObj(new BgObj(m_Res->GetSprite("background"),_GAMEROOM_L,0,true));
	m_player = new PlayerObj(
		m_Res->GetAnimation("Player"),
		m_Res->GetSprite("Spr1"),
		m_Res->GetSprite("Spr2"),
		m_Res->GetSprite("Spr3"),
		m_Res->GetSprite("PlayerShift"),
		m_Res->GetSprite("PlayerMainBullet"),
		m_Res->GetSprite("PlayerTraceBulletA"),
		m_Res->GetSprite("PlayerTraceBulletB"),
		m_Res->GetSprite("PlayerTraceBulletC"),
		m_Res->GetSprite("PlayerBoom"),
		m_Res->GetEffect("MainBulletEffect"),
		m_Res->GetEffect("BoomEffect"),
		m_Res->GetEffect("ShiftEffect"),
		m_Res->GetParticleSystem("BoomPart"),
		_def_speed,_def_startx,_def_starty
		);

	m_iEnermy = m_GameLayer.size();
}

GameRoom::~GameRoom() 
{
	Environment::Channel_StopAll();
	ClearAll();
	m_Res->Purge();
	delete m_Res;
}

void GameRoom::AddGameObj( GameObj* obj )
{
	m_GameLayer.push_back(obj);
}

void GameRoom::DelGameObj( GameObj* obj )
{
	std::iter_swap(std::find(m_GameLayer.begin(),m_GameLayer.end(),obj),m_GameLayer.end()-1);
	m_GameLayer.pop_back();
}

void GameRoom::DelGameObj( int num )
{
	std::iter_swap(m_GameLayer.begin()+num,m_GameLayer.end()-1);
	m_GameLayer.pop_back();
}


bool GameRoom::FrameFunc()
{
	m_livetime += Environment::GetDelta();
	Environment::Channel_Resume(m_musicPlayer);
	EnermyInfo tmp = ScriptEngine::Controller("Script//Script1.lua",m_livetime);
	if (tmp.hp>0)
	AddGameObj(new EnermyObj(
		m_Res->GetAnimation(tmp.enermy.c_str()),
		m_Res->GetSprite(tmp.bullet.c_str()),
		tmp.x,tmp.y,tmp.time,tmp.hp,tmp.control,tmp.bulletType
		));
	BossInfo temp = ScriptEngine::BossController(m_livetime);
	if (temp.hp>0) {
		AddGameObj(new BossObj(m_Res->GetAnimation(temp.BossName.c_str()),
			temp.x,
			temp.y,
			temp.time,
			temp.hp,
			temp.control,
			m_Res->GetSprite(temp.Bullet1.c_str()),
			m_Res->GetSprite(temp.Bullet2.c_str()),
			m_Res->GetSprite(temp.Bullet3.c_str()))
			);
	}
	std::for_each(m_GameLayer.begin(),m_GameLayer.end(),boost::mem_fn(&GameObj::Update));
	m_player->Update();
	if (m_pickedEnermy==NULL){
		m_pickedEnermy = pickEnermy();
	}
	if (m_pickedEnermy!=NULL){
		if (m_pickedEnermy->getX()>_WINDOWS_WIDTH || m_pickedEnermy->getX()<0 || m_pickedEnermy->getY()<0 || m_pickedEnermy->getY()>_WINDOWS_HEIGHT)
			m_player->unlockTarget();
		else m_player->lockTarget(m_pickedEnermy->getX(),m_pickedEnermy->getY());
	}
	for (unsigned int i=m_iEnermy;i<m_GameLayer.size();i++) {
		hgeRect tmp;
		
		m_score+=((EnermyObj*)m_GameLayer[i])->MakeDmg(
		m_player->checkCollision(m_GameLayer[i]->getCollision(&tmp))
		);

		m_player->MakeDmg(
			((EnermyObj*)m_GameLayer[i])->checkCollision(m_player->getCollision(&tmp))
		);

		if (((EnermyObj*)m_GameLayer[i])->isClear()) {
			if ((EnermyObj*)m_GameLayer[i]==m_pickedEnermy){
				m_pickedEnermy = NULL;
				m_player->unlockTarget();
			}
			DelGameObj(i);
		}
	}
	if (Environment::GetKeyState(HGEK_ESCAPE)) {
		Environment::Channel_Pause(m_musicPlayer);
		Environment::pushRoom(new InsideRoom("InsideRoom.res"));
	}
	if (m_isGameover) {
		Environment::Channel_Pause(m_musicPlayer);
		Environment::pushRoom(new EndRoom("EndRoom.res"));
	}
#ifdef _DEBUG
	if (Environment::GetKeyState(HGEK_V)) {
		Environment::Channel_Pause(m_musicPlayer);
		Environment::pushRoom(new EndRoom("EndRoom.res"));
	}
#endif
	static float vtime;
	if (m_livetime>100 && m_GameLayer.size()<=2) {
		vtime+=Environment::GetDelta();
		if (vtime>2) GameRoom::setGameOver();
	} else vtime = 0;
	return false;
}

bool GameRoom::RenderFunc()
{
	std::for_each(m_GameLayer.begin(),m_GameLayer.end(),boost::mem_fn(&GameObj::Render));
	m_Res->GetFont("font")->printf(580,100,HGETEXT_LEFT,"Score:%d\n\nLife:%d\nSpells:%d",m_score,m_player->getLife(),m_player->getBoom());
	m_player->Render();
	return false;
}


void GameRoom::ClearAll()
{
	std::for_each(m_GameLayer.begin(),m_GameLayer.end(),delete_object());
}

EnermyObj* GameRoom::pickEnermy()
{
	EnermyObj * Best = NULL;
	float MinDist = 1e10;
	for (unsigned i = m_iEnermy; i != m_GameLayer.size(); ++i){
		EnermyObj * enyptr = (EnermyObj *) m_GameLayer[i];
		if (!enyptr->isClear())
			if (Best == NULL) {
				Best = enyptr;
				MinDist = sqr(m_player->getX() - enyptr->getX())+sqr(m_player->getY() - enyptr->getY());
			} else {
				float NewDist = sqr(m_player->getX() - enyptr->getX())+sqr(m_player->getY() - enyptr->getY());
				if (NewDist < MinDist){
					Best = enyptr;
					MinDist = NewDist;
				}
			}
	}
	return Best;
}

void GameRoom::Boom()
{
	for (unsigned int i = m_pToDev->m_iEnermy;i<m_pToDev->m_GameLayer.size();i++)
	{
		((EnermyObj*)m_pToDev->m_GameLayer[i])->MakeDmg(_PLAYER_BOOM_DMG);
		((EnermyObj*)m_pToDev->m_GameLayer[i])->clearBullet();
	}
}

void GameRoom::setGameOver()
{
	m_pToDev->m_isGameover = true;
}

bool GameRoom::isGameOver()
{
	return m_pToDev->m_isGameover;
}
